.TITLE MDSUB .IDENT /16.00/ ; ; Copyright (c) 1995-1999 by Mentec, Inc., U.S.A. ; All rights reserved. ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; D. N. CUTLER 4-AUG-73 ; ; MODIFIED FOR RSX-11M-PLUS VERSION 4.0 BY: ; ; J. R. (LITTLE RALPHY) KAUFFMAN ; ; MODIFIED FOR RSX-11M-PLUS VERSION 4.3 BY: ; ; B. S. MCCARTHY 28-JUN-89 15.00 ; ; BM421 -- ENHANCE DOCUMENTATION OF $VOLVD, ADD ABILITY ; TO RESET VOLUME VALID OF A MOUNTED VOLUME AS ; LONG AS IT HAS NO ACP. THIS ALLOWS THE BRU FIX ; TO THE RX50 DOOR PROBLEM ON VAX-COPROCESSOR/RSX ; TO WORK ON STOCK RSX SYSTEMS. ; ; Modified for RSX-11M-PLUS Version 4.5 by: ; ; D. Carroll 22-May-1990 15.10 ; DC123 - Include support to track shadow recording errors ; detected on a shadow pair in $SHSAV ; ; D. Carroll 19-Oct-1993 15.11 ; DC241 - Include correction to allow $CVLBN to handle ; quotients of 16 bit magnitude. ; ; D. Carroll 04-August-1994 15.12 ; DC298 - Correct $DLNK subroutine to not deallocate ; the UMB if other packets are present when ; delinking the last ML node in the list. ; ; Modified for RSX-11M-PLUS V4.6 by: ; ; D. Carroll 18-Oct-1995 15.13 ; DC404 - Include PSECT statement to allow ICB pool to ; be fully extended during sysgen ; ; D. Carroll 08-Jan-1996 16.00 ; DC430 - Include support for 32-bit LBN devices ; and 2,4 retreival pointers ; ; ; I/O RELATED ROUTINES ; ; ROUTINES USED BY FILES-11 AND MASS STORAGE DRIVERS ; ; MACRO LIBRARY CALLS ; .MCALL F11DF$,HDRDF$,HWDDF$,PCBDF$,PKTDF$,SHDDF$,TCBDF$ F11DF$ ;DEFINE WINDOW AND LOCK BLOCK OFFSETS HDRDF$ ;DEFINE TASK HEADER OFFSETS HWDDF$ ;DEFINE HARDWARE REGISTERS PCBDF$ ;DEFINE PARTITION CONTROL BLOCK OFFSETS PKTDF$ ;DEFINE I/O PACKET OFFSETS SHDDF$ ;DEFINE SHADOW RECORDING OFFSETS TCBDF$ ;DEFINE TASK CONTROL BLOCK OFFSETS .IIF DF,K$$DAS&I$$CBP, .PSECT EXEC1 ;DC404 ;DC404 ;+ ; **-$DEATR-DEALLOCATE ATTRIBUTE BLOCK ; ; THIS ROUTINE IS CALLED TO DEALLOCATE AN ATTRIBUTE BLOCK ALLOCATED ; BY QIO PROCESSING OF A USER FILE ATTRIBUTE LIST. ; ; INPUTS: ; ; R0=ADDRESS OF ATTRIBUTE BLOCK. ; ; OUTPUTS: ; ; ALL I/O COUNTS ASSOCIATED WITH THE BLOCK ARE DECREMENTED. ;- $DEATR::MOV R0,-(SP) ;SAVE ADDRESS OF BLOCK MOV #6,-(SP) ;SET MAX COUNT OF ATTRIBUTES 60$: TSTB (R0) ;IS THERE ANOTHER ATTRIBUTE? BEQ 70$ ;IF EQ NO MOV R0,-(SP) ;SAVE POINTER INTO BLOCK MOV 2(R0),R0 ;POINT TO ATTACHMENT DESCRIPTOR CALL $DECIO ;DECREMENT I/O COUNT MOV (SP)+,R0 ;RESTORE POINTER INTO ATTRIBUTE BLOCK ADD #8.,R0 ;POINT TO NEXT ENTRY IN BLOCK DEC (SP) ;ANY MORE TO GO? BNE 60$ ;IF NE YES 70$: TST (SP)+ ;POP COUNT MOV (SP)+,R0 ;RESTORE BLOCK POINTER MOV #I.ATRL,R1 ;SET COUNT TO RELEASE CALLR $DEACB ;DEALLOCATE BLOCK AND RETURN ;+ ; **-$CVLBN-CONVERT LOGICAL BLOCK NUMBER TO DISK PARAMETERS ; ; THIS SUBROUTINE WILL CONVERT THE SPECIFIED LOGICAL BLOCK NUMBER ; TO A SECTOR/TRACK/CYLINDER ADDRESS. ; ; INPUTS: ; ; (SAME AS $BLKCK OUTPUTS) ; R0=LOW PART OF LBN ; R2=HIGH PART OF LBN ; R3=I/O PACKET ADDRESS ; R5=UCB ADDRESS ; ; OUTPUTS: ; ; R0=SECTOR NUMBER ; R1=TRACK NUMBER ; R2=CYLINDER NUMBER ;- $CVLBN::MOV R0,R1 ;SHUFFLE LOW LBN MOV R2,R0 ;SHUFFLE HIGH LBN MOVB U.PRM(R5),R2 ;SET DIVISOR TO SECTORS PER TRACK MOV R0,-(SP) ; SAVE HIGH ORDER LBN PORTION MOV R1,-(SP) ; AND LOW ORDER LBN PORTION DIV R2,R0 ; CALCULATE SECTOR NUMBER BVC 10$ ; IF VC, NO OVERFLOW OF 15 BITS MOV (SP)+,R0 ; RESTORE LOW ORDER LBN MOV (SP)+,R1 ; AND HIGH ORDER PORTION CALL $DBDIV ; PERFORM DOUBLE DIVIDE TST (PC)+ ; SKIP STACK CLEAN UP 10$: MOV (SP)+,(SP)+ ; CLEAN STACK MOV R1,-(SP) ;SAVE SECTOR NUMBER MOV R0,R1 ;SET NEW DIVIDEND CLR R0 ;CLEAR HIGH BITS MOVB U.PRM+1(R5),R2 ;SET DIVISOR TO TRACKS PER CYLINDER DIV R2,R0 ;CALCULATE TRACK AND CYLINDER MOV R0,R2 ;COPY CYLINDER NUMBER MOV (SP)+,R0 ;RETREIVE SECTOR NUMBER RETURN ; ;+ ; **-$BLKCK-LOGICAL BLOCK CHECK ROUTINE ; **-$BLKC1-LOGICAL BLOCK CHECK ROUTINE (ALTERNATE ENTRY) ; **-$BLKC2-LOGICAL BLOCK CHECK ROUTINE (ALTERNATE ENTRY FOR QUEUE OPT) ; ; THIS ROUTINE IS CALLED BY I/O DEVICE DRIVERS TO CHECK THE STARTING ; AND ENDING LOGICAL BLOCK NUMBERS OF AN I/O TRANSFER TO A FILE ; STRUCTURED DEVICE. IF THE RANGE OF BLOCKS IS NOT LEGAL, THEN $IODON ; IS ENTERED WITH A FINAL STATUS OF "IE.BLK" AND A RETURN TO THE ; DRIVER'S INITIATOR ENTRY POINT IS EXECUTED. ELSE A RETURN TO THE ; DRIVER IS EXECUTED. ; ; $BLKC2 RETURNS TO $QOPDN IN $DRQRQ IF THERE IS AN ERROR INSTEAD OF ; THE DRIVER'S INITIATOR ENTRY POINT. THIS ALLOWS THE QUEUE ; OPTIMIZATION CODE TO USE BLKCK ; ; INPUTS: ; ; R1=ADDRESS OF I/O PACKET. ; R5=ADDRESS OF THE UCB. ; ; OUTPUTS: ; ; IF THE CHECK FAILS, THEN $IODON IS ENTERED WITH A FINAL STATUS ; OF "IE.BLK" AND A RETURN TO THE DRIVER'S INITIATOR ENTRY POINT ; IS EXECUTED. ; ; IF THE CHECK SUCCEEDS, THEN THE FOLLOWING REGISTERS ARE RETURNED ; R0=LOW PART OF LOGICAL BLOCK NUMBER. ; R1=POINTS TO I.PRM+12 (LOW PART OF USER LBN) ; R2=HIGH PART OF LOGICAL BLOCK NUMBER. ; R3=ADDRESS OF I/O PACKET. ;- .ENABL LSB $BLKC2::MOV #1,-(SP) ;FLAG THIS AS THE BLKC2 ENTRY BR 4$ ;CONTINUE $BLKCK::CLR -(SP) ;FLAG THIS AS A NORMAL ENTRY 4$: MOV R1,R3 ;SAVE ADDRESS OF I/O PACKET .IF DF,E$$LBN ;EXTENDED LBN SUPPORT ;DC430 ADD #I.PRM+12,R1 ;POINT PAST HIGH PART OF LBN ;DC430 BIT #DV.32B,U.CW1(R5) ; DEVICE SUPPORT 32-BIT LBNS ;DC430 BNE BLKC3 ;YES, DON'T ZERO IT ;DC430 CLRB -1(R1) ;CLEAR EXCESS BYTE ;DC430 .IFF ;DF,E$$LBN ;DC430 ADD #I.PRM+11,R1 ;POINT PAST HIGH PART OF LBN ;DC430 CLRB (R1)+ ;CLEAR EXCESS BYTE ;DC430 .ENDC ;DF,E$$LBN ;DC430 BR BLKC3 ;SKIP THE ALTERNATE ENTRY ;**-2 $BLKC1::CLR -(SP) ;FLAG THIS AS A NORMAL ENTRY BLKC3: MOV (R1),R0 ;GET LOW PART OF LBN MOV -(R1),R2 ;GET HIGH PART OF LBN MOV I.PRM+4(R3),-(SP) ;GET NUMBER OF BYTES TO TRANSFER ADD #777,(SP) ;ROUND TO NEXT BLOCK ROR (SP) ;CALCULATE NUMBER OF BLOCKS IN HIGH BYTE CLRB (SP) ;CLEAR EXCESS BYTE SWAB (SP) ;CALCULATE NUMBER OF BLOCK IN TRANSFER ADD (SP)+,R0 ;CALCULATE HIGHEST BLOCK NUMBER + 1 .IF DF,E$$LBN ; EXTENDED LOGICAL BLOCK NUMBERS ;DC430 ADC R2 ; DOUBLE PRECISION CARRY ;DC430 BCS 20$ ; IF CS, OVERFLOW ;DC430 MOV U.CW2(R5),-(SP) ; SAVE THE DEVICE SIZE (MSP) ;DC430 BIT #DV.32B,U.CW1(R5) ; USING 32-BIT LBNS ;DC430 BNE 5$ ; IF NE, YES, DO FULL COMPARE ;DC430 CLRB 1(SP) ; ZERO HIGH ORDER PORTION OF LBN ;DC430 5$: CMP R2,(SP)+ ; DO THE COMPARE ;DC430 .IFF ;DF,E$$LBN ;DC430 ADCB R2 ; BCS 20$ ;IF CS ILLEGAL BLOCK NUMBER CMPB R2,U.CW2(R5) ;HIGH PART OF LBN LEGAL? .ENDC ;DF,E$$LBN ;DC430 BHI 20$ ;IF HI NO BLO 10$ ;IF LO YES CMP R0,U.CW3(R5) ;LOW PART OF LBN LEGAL? BHI 20$ ;IF HI NO 10$: MOV (R1)+,R2 ;RETRIEVE HIGH PART OF LBN MOV (R1),R0 ;RETRIEVE LOW PART OF LBN TST (SP)+ ;CLEAN THE STACK RETURN ; 20$: TST (SP)+ ;TEST THE ENTRY FLAG BEQ 30$ ;RETURN TO THE DRIVER'S INITIATOR TST (SP)+ ;REMOVE DRIVERS EXTRA STACK ENTRY MOV #$QOPDN,(SP) ;SETUP FOR QUEUE OPTIMIZATION RETURN MOV #IE.BLK&377,R0 ;SET FINAL I/O STATUS CALLR $IOFIN ;AND FINISH UP THE I/O 30$: MOV (R5),R0 ;GET ADDRESS OF DEVICE DCB MOV @D.DSP(R0),(SP) ;REPLACE RETURN ADDRESS TO INITIATOR MOV #IE.BLK&377,R0 ;SET FINAL I/O STATUS JMP $IOALT ;AND COMPLETE THE I/O .DSABL LSB ;+ ; **-$SHFND-FIND SHADOW RECORDING PACKET ON UMB ML NODE LIST. ; **-$SHFN1-FIND SHADOW RECORDING PACKET ON UMB ML NODE LIST (ALT ENTRY) ; ; THIS ROUTINE WILL SEARCH THE LIST WHOSE ROOT IS AT M.LHD FOR ; AN ML NODE THAT EITHER POINTS TO OR CONTAINS THE I/O PACKET ; SPECIFIED AS INPUT. ; ; INPUTS: ; ; R3=I/O PACKET ADDRESS FOR WHICH TO SEARCH. ; R5=UCB ADDRESS. ; ; OUTPUTS: ; ; C=0 (SUCCESS -- FOUND I/O PACKET) ; ; R2=OTHER I/O PACKET. ; R4=ML NODE ADDRESS. ; ; C=1 (FAILURE -- NO PACKET OR DISK NOT SHADOWED) ; ; R2,R4 DESTROYED. ; ; ALL OTHER REGISTERS PRESERVED. ;- .IF DF S$$HDW .ENABL LSB $SHFND::BIT #DV.MSD,U.CW1(R5) ;IS THIS A MASS STORAGE DEVICE? BEQ 30$ ;IF EQ NO -- CAN'T SHADOW THIS DEVICE $SHFN1::BIT #DV.SQD,U.CW1(R5) ;COULD IT BE A MAGTAPE? BNE 30$ ;IF NE YES -- CAN'T SHADOW ; ; THE ABOVE STATEMENTS DEFINE THOSE DEVICES WHICH HAVE THE CELL ; U.UMB IN THEIR UCB'S. NOW SEE IF U.UMB IS NON-ZERO, WHICH ; MEANS THE DEVICE IS CURRENTLY SHADOW RECORDED. ; MOV U.UMB(R5),R4 ;GET UMB ADDRESS BEQ 30$ ;IF EQ NO UMB, THEREFORE NOT SHADOWED ; ; SHADOW RECORDING IS ENABLED ON THIS DISK. NOW SEE IF THE PACKET ; SPECIFIED IS FROM THE REPLACEMENT CONTROL TASK AND IF IT IS, SKIP ; OVER IT. ; CMP $RCTPT,I.TCB(R3) ;IS THIS I/O PACKET FOR RCT? BEQ 30$ ;IF EQ YES, EXIT ; ; THE SPECIFIED PACKET IS NOT FROM THE REPLACEMENT CONTROL TASK. NOW SEE ; IF THE PACKET SPECIFIED IS IN THE LIST OFF THE UMB. ; ADD #M.LHD+ML.PKT,R4 ;START SCAN AT PROPER PLACE 10$: MOV ML.LNK-ML.PKT(R4),R4 ;GET NEXT ML NODE BEQ 30$ ;IF EQ NONE LEFT MOV ML.PRI(R4),R2 ;GET PRIMARY PACKET ADDRESS CMP R2,R3 ;IS THIS THE INPUT PACKET? BEQ 20$ ;IF EQ YES ADD #ML.PKT,R4 ;POINT TO SECONDARY PACKET IN NODE CMP R4,R3 ;IS OURS THE SECONDARY PACKET? BNE 10$ ;IF NE NO -- GO OFF TO TRY AGAIN SUB #ML.PKT,R4 ;MOVE BACK TO MAKE R4=ADDRESS ML NODE BR 25$ 20$: MOV R4,R2 ;COPY I/O PACKET ADDRESS ADD #ML.PKT,R2 ;POINT TO SECONDARY PACKET 25$: CLC ;SHOW SUCCESS RETURN 30$: SEC ;SHOW FAILURE RETURN .DSABL LSB ;+ ; **-$DLNK-DELINK AN ML NODE FROM THE LIST IN THE UMB. ; ; THIS ROUTINE WILL DELINK THE SPECIFIED ML NODE FROM THE LIST ; OF ML NODES IN THE SPECIFIED UMB. ; ; INPUTS: ; ; R3=I/O PACKET ADDRESS. ; R4=ML NODE. ; ; OUTPUTS: ; ; NODE SPECIFED IN R4 IS DELINKED. ; ; REGISTERS R2,R3 DESTROYED. ;- $DLNK:: MOV I.UCB(R3),R3 ;GET UCB ADDRESS FOR UMB MOV R3,-(SP) ;SAVE UCB ADDRESS ON STACK MOV U.UMB(R3),R3 ;GET UMB ADDRESS FROM UCB ADD #M.LHD,R3 ;POINT TO LISTHEAD 10$: MOV R3,R2 ;SAVE LAST NODE MOV (R3),R3 ;GET NEXT NODE BNE 20$ ;IF NE THERE IS ONE BPT ;DEBUGGING BPT -- CAN'T DELINK ;NODE NOT FOUND 20$: CMP R3,R4 ;IS THIS THE ONE? BNE 10$ ;IF NE NO -- TRY AGAIN MOV (R3),(R2) ;DELINK THE NODE BNE 30$ ;IF EQ LIST NOT YET EMPTY ; ; THE LIST IS EMPTY. SEE IF WE ARE SUPPOSED TO DEALLOCATE THE UMB. ; MOV (SP),R3 ;GET UCB ADDRESS BACK MOV U.UMB(R3),R2 ;GET UMB ADDRESS BIT #MS.MDA,M.STS(R2) ;IS UMB MARKED FOR DEALLOCATION? BEQ 30$ ;IF EQ NO -- EXIT NOW TST M.LHD(R2) ; ARE THERE ANY OTHER PACKETS LEFT? BNE 30$ ; YES, DO NOT DELETE THE UMB YET ... ; ; UMB IS MARKED FOR DEALLOCATION. WE WILL NOW RELEASE THE STORAGE, ; AND REMOVE THE TWO POINTERS FROM THE UCBS. ; MOV M.UCBS(R2),R3 ;GET PRIMARY UCB CLR U.UMB(R3) ;CLEAR PRIMARY UCB MOV M.UCBS+2(R2),R3 ;GET SECONDARY UCB CLR U.UMB(R3) ;CLEAR SECONDARY UCB MOV R0,-(SP) ;SAVE STATUS MOV R1,-(SP) ;SAVE R1 ; ; WE MUST DELINK THE UMB FROM THE SYSTEM LIST OF UMB'S ; MOV #$SHUMB,R0 ;GET START OF LIST 25$: MOV R0,R1 ;MAKE CURRENT THE NEW OLD PTR MOV (R1),R0 ;GET NEW CURRENT PTR .IF DF R$$DER BNE 27$ ;IF NE NOT END OF LIST BPT ;OOPPS -- CNT'T FIND IN LIST 27$: ;REFERENCE LABEL .ENDC CMP R0,R2 ;IS THIS THE NODE? BNE 25$ ;IF NE NO MOV (R2),(R1) ;DELINK NODE FROM UMB LIST MOV #M.LGH,R1 ;SET LENGTH TO DEALLOCATE MOV R2,R0 ;SET ADDRESS OF UMB CALL $DEACB ;DEALLOCATE UMB MOV (SP)+,R1 ;RESTORE R1 MOV (SP)+,R0 ;RESTORE R0 30$: TST (SP)+ ;CLEAN UCB ADDRESS FROM STACK RETURN ;+ ; **-$SHSAV-SAVE CURRENT STATUS IN THE ML NODE. ; ; THIS ROUTINE WILL SAVE R0 AND R1 IN THE CORRECT PLACE IN THE ; CURRENT I/O PACKET. IT WILL ALSO INCREMENT THE COUNT OF I/O ; PACKETS FINISHED FOR THIS ML NODE. ; ; INPUTS: ; ; R0=FIRST STATUS WORD. ; R1=SECOND STATUS WORD. ; R3=I/O PACKET ADDRESS. ; R4=ML NODE ADDRESS. ; R5=UCB ADDRESS. ; ; OUTPUTS: ; ; COUNT OF FINISHED I/O PACKETS FOR THIS ML NODE IS ONE ; GREATER. STATUS SAVED IN I/O PACKET. IF THE STATUS IS ; ERROR, THEN THE UMB ERROR COUNT IS INCREMENTED. ; ; In addition, if we are able to disable devices in the shadow ; pair, a check will be done, and if so, the device will be disabled ; from further reads. However, writes will still be shadowed ; ; ALL REGISTERS PRESERVED. ;- $SHSAV::INCB ML.DNC(R4) ;SHOW ONE PACKET FINISHED MOV R0,I.R0(R3) ;SAVE STATUS MOV R1,I.R1(R3) ;SAVE STATUS .IF DF,S$$HLS ; shadow load sharing MOV R2,-(SP) ; Save R2 for a bit MOV #,R2 ; Assume primary device CMP R3,ML.PRI(R4) ; Is this the primary packet BEQ 5$ ; if EQ, yes, was primary MOV #,R2 ; Set secondary device 5$: MOV R5,-(SP) ; Save the UCB address MOV U.UMB(R5),R5 ; Get the ML node address .IFTF ;DF,S$$HLS TSTB R0 ;WAS THE OPERATION SUCCESSFUL? BPL 20$ ;IF PL, YES .IFF ;DF,S$$HLS MOV R5,-(SP) ;SAVE THE UCB ADDRESS MOV U.UMB(R5),R5 ;GET THE ML NODE ADDRESS .IFT ;DF,S$$HLS TSTB M.STS(R5) ; do we perform load balancing? BPL 10$ ; if PL, nope, don't check for disable ... MOVB M.FLG(R5),-(SP) ; get the flags byte MOV R2,-(SP) ; save the mask word ... BIC #^C,(SP) ; isolate down to an increment mask ADD (SP)+,(SP) ; perform the increment ... BITB R2,(SP) ; did we overflow the mask? BEQ 6$ ; if EQ, yes, we did try the disable ... MOVB (SP)+,M.FLG(R5) ; reset the updated error count BR 7$ ; and rejoin common code ... 6$: TST (SP)+ ; clean up the stack BICB R2,M.FLG(R5) ; reset the counter to zero ... BITB #MS.DSB,M.STS(R5) ; Can we disable a device? BEQ 7$ ; if EQ, nope ... BITB #MS.CHP,M.STS(R5) ; are we doing an update? BNE 7$ ; if NE, yes, don't disable the primary SWAB R2 ; set up the disable bit ... BISB R2,M.STS(R5) ; disable the appropriate device MOV #,-(SP) ; set up the mask word BIC R2,(SP) ; get the "other" bit BICB (SP)+,M.STS(R5) ; so we don't disable both devices 7$: .IFTF ;DF,S$$HLS ; reference label INCB M.ERC(R5) ;INCREMENT THE ERROR COUNT BNE 10$ ;IF NE, DIDN'T OVERFLOW DECB M.ERC(R5) ;LOCK THE COUNT AT 255. BISB #MF.DSE,M.FLG(R5) ; disable SHE... logging at the point 10$: MOV (SP)+,R5 ;RESTORE THE UCB ADDRESS .IFT ;DF,S$$HLS MOV (SP)+,R2 ; Restore the scratch register RETURN ; To caller ;+ ; Succesful I/O completion, the drive isn't fatally wounded ... ; Re-enable the device for further I/O. ;- 20$: SWAB R2 ; settup for a full word clear ... BIC R2,M.STS(R5) ; Re-enable I/O to this device BR 10$ ; and finish up .IFF ;DF,S$$HLS 20$: RETURN ;TO CALLER .ENDC ;DF,S$$HLS ;+ ; **-$CKLBN-DETERMINE IF LBN RANGE IN AN ML NODE IS BELOW THE FENCE. ; ; THIS ROUTINE WILL DETERMINE IF A RANGE OF LOGICAL BLOCKS ; SPECIFIED IN AN ML NODE IS BELOW THE FENCE IN THE UMB. ; ; INPUTS: ; ; R4=ML NODE ADDRESS. ; R5=UMB ADDRESS. ; ; OUTPUTS: ; ; C=0 IF THE LBN RANGE IN THE ML NODE IF BELOW THE FENCE. ;- $CKLBN::MOV R0,-(SP) ;SAVE R0 MOV R1,-(SP) ;SAVE R1 .IF DF,E$$LBN ;DC430 MOV ML.LBN(R4),R0 ; GET HIGH ORDER PART OF LBN ;DC430 .IFF ;DF,E$$LBN ;DC430 MOVB ML.LBN(R4),R0 ;GET HIGH BYTE OF LBN ;DC430 .IFTF ;DF,E$$LBN ;DC430 MOV ML.PKT+I.PRM+4(R4),R1 ;GET BYTE COUNT ;**-1 ADD #777,R1 ;ROUND UP TO NEXT BLOCK ROR R1 ;CONVERT TO WORDS CLRB R1 ;CLEAR RESIDUAL BITS SWAB R1 ;SWAP NUMBER OF BLOCKS TO LOW BYTE ADD ML.LBN+2(R4),R1 ;CALCALATE LAST LBN IN TRANSFER ADC R0 ; .IFT ;DF,E$$LBN ;DC430 CMP M.ELBN+2(R5),R0 ;OVERLAP? ;DC430 .IFF ;DF,E$$LBN ;DC430 CMPB M.LBN(R5),R0 ;OVERLAP? ;DC430 .ENDC ;DF,E$$LBN ;DC430 BNE 100$ ;IF LO CARRY IS SET, IF HI CARRY IS CLR ;**-1 CMP M.LBN+2(R5),R1 ;SET UP CONDITION CODES 100$: MOV (SP)+,R1 ;RESTORE R1 MOV (SP)+,R0 ;RESTORE R0 RETURN ; .ENDC ; DF S$$HDW ;+ ; **-$MPPKT-MAP I/O PACKET FUNCTION ; ; THIS ROUTINE IS CALLED TO MAP A READ/WRITE VIRTUAL FUNCTION IN AN I/O PACKET ; TO A READ/WRITE LOGICAL FUNCTION. IF THE CURRENT WINDOW DOES NOT MAP THE VIRTU ; FUNCTION, THEN A FAILURE INDICATION IS RETURNED. ELSE IF THE WINDOW COMPLETELY ; MAPS THE VIRTUAL FUNCTION, THEN THE LOGICAL BLOCK NUMBER IS STORED IN THE I/O ; PACKET AND THE READ/WRITE VIRTUAL FUNCTION IS CONVERTED TO ITS LOGICAL COUNTER ; PART. ELSE THE PARTIAL MAPPING RESULTS ARE RETURNED TO THE CALLER. ; ; INPUTS: ; ; R1=ADDRESS OF THE I/O PACKET. ; R5=UCB ADDRESS OF DEVICE. ; ; OUTPUTS: ; ; C=1 IF MAPPING FAILURE. ; C=0 IF MAPPING WAS SUCCESSFUL. ; IF R0 EQ 0, THEN ; I.FCN+1(R1)=IO.WLB/IO.RLB. ; I.PRM+10(R1)=HIGH PART OF MAPPED LBN. ; I.PRM+12(R1)=LOW PART OF MAPPED LBN.. ; ELSE ; R0=NUMBER OF BLOCKS NOT MAPPED. ; R2=HIGH PART OF MAPPED LBN. ; R3=LOW PART OF MAPPED LBN. ; ; R1 IS PRESERVED ACROSS CALL. ;- $MPPKT::MOV I.LN2(R1),R0 ; GET IMAGE OF LUT2 OR ADDRESS OF LUT2 BIT #1,R0 ; ADDRESS? BNE 5$ ; IF NE NO .IF DF X$$HDR MOV KISAR6,-(SP) ; SAVE CURRENT MAPPING MOV I.TCB(R1),R2 ; GET TCB ADDRESS MOV T.PCB(R2),R2 ; GET PCB ADDRESS OF TASK REGION MOV P.REL(R2),KISAR6 ; ASSUME WE NEED TO MAP HEADER .IFTF MOV (R0),R0 ; GET CONTENTS OF LUT2 .IFT MOV (SP)+,KISAR6 ; RESTORE MAPPING .ENDC 5$: BIC #1,R0 ; CLEAR POSSIBLE INTERLOCK MOV R0,$IOTMP ; SAVE FOR LATER MOV R1,-(SP) ; SAVE I/O PACKET ADDRESS MOV I.PRM+12(R1),R3 ; PICKUP LOW PART OF VBN MOV I.PRM+10(R1),R2 ; PICKUP HIGH PART OF VBN MOV I.PRM+4(R1),R0 ; PICKUP LENGTH OF TRANSFER IN BYTES MOV $IOTMP,R1 ; SET WINDOW BLOCK ADDRESS CALL $MPVBN ;MAP VIRTUAL BLOCK NUMBER MOV (SP)+,R1 ;RETRIEVE I/O PACKET ADDRESS BCS 20$ ;IF CS MAPPING FAILURE TST R0 ;REQUEST COMPLETELY MAPPED? BNE 20$ ;IF NE NO MOVB R2,I.PRM+10(R1) ;SET HIGH PART OF LBN .IF DF,E$$LBN ; EXTENDED LBNS ;DC430 BIT #DV.32B,U.CW1(R5) ; DEVICE SUPPORT EXTENDED LBNS ;DC430 BEQ 7$ ; IF EQ, NOPE, CONTINUE ;DC430 MOV R2,I.PRM+10(R1) ;SET HIGH PART OF LBN ;DC430 7$: ;REFERENCE LABEL ;DC430 .ENDC ;DF,E$$LBN ;DC430 MOV R3,I.PRM+12(R1) ;SET LOW PART OF LBN MOV #IO.RLB,-(SP) ;ASSUME READ REQUEST CMPB #IO.WVB/256.,I.FCN+1(R1) ;WRITE VIRTUAL FUNCTION? BNE 10$ ;IF NE NO MOV #IO.WLC,(SP) ;ASSUME WRITE CHECK ; ASSUME WI.WCK,100000 TST @$IOTMP ;DATA CHECKING REQUESTED? BMI 10$ ;IF MI YES CLRB (SP) ;DEMOTE TO WRITE LOGICAL (IO.WLB) 10$: MOV (SP)+,I.FCN(R1) ;SET NEW FUNCTION CODE MOV R1,R3 ;SAVE I/O PACKET ADDRESS MOV I.PRM(R3),R1 ;GET RELOCATION BIAS MOV I.PRM+2(R3),R2 ;GET DISPLACEMENT ADDRESS CALL $MPPHY ;MAP TO 18 BIT PHYSICAL ADDRESS MOV R1,I.PRM(R3) ;INSERT 18 BIT PHYSICAL ADDRESS BACK MOV R2,I.PRM+2(R3) ;INTO I/O PACKET MOV R3,R1 ;RESTORE I/O PACKET ADDRESS CLC ;MAKE SURE CARRY IS CLEAR 20$: RETURN ; ;+ ; **-$MPVBN-MAP VIRTUAL BLOCK NUMBER ; ; THIS ROUTINE IS CALLED TO MAP A VIRTUAL BLOCK NUMBER (VBN) TO A LOGICAL BLOCK ; NUMBER (LBN) VIA A WINDOW BLOCK THAT CONTAINS A SET OF MAPPING POINTERS. ; ; INPUTS: ; ; R0=NUMBER OF CONSECUTIVE BYTES THAT MUST BE MAPPED. ; R1=ADDRESS OF THE WINDOW BLOCK. ; R2=HIGH PART OF VBN. ; R3=LOW PART OF VBN. ; ; OUTPUTS: ; ; C=1 IF VBN CANNOT BE MAPPED VIA WINDOW BLOCK. ; C=0 IF VBN SUCCESSFULLY MAPPED TO LBN. ; PARTIAL MAPPING IS A SUCCESS. ; R0=NUMBER OF UNMAPPED BLOCKS. ; R2=HIGH PART OF LBN. ; R3=LOW PART OF LBN. ; R4 & R5 PRESERVED. ; ; IF DATA CACHING IS SUPPORTED, THE FOLLOWING RETRIEVAL ; INFORMATION IS PROVIDED VIA CELLS IN SYSCM: ; ; $DCCEL - CURRENT EXTENT LENGTH (IF SUCCESSFUL MAP) ; (0 INDICATES INFORMATION NOT AVAILABLE) ; $DCCEB - CURRENT EXTENT BASE LBN (DITTO) ; $DCNEL - NEXT EXTENT LENGTH (IF AVAILABLE) ; (0 INDICATES INFORMATION NOT AVAILABLE) ; $DCNEB - NEXT EXTENT BASE LBN (DITTO) ; $DCSTS - STATUS INFORMATION FROM WINDOW BLOCK ; ;- $MPVBN::SAVNR ;SAVE NONVOLATILE REGISTERS .IF DF D$$CHE MOVB W.STS(R1),$DCSTS ;GET INFORMATION FROM WINDOW BLOCK .ENDC ; DF D$$CHE .IF DF P$$WND MOV KISAR5,R5 ;SAVE SYSTEM APR5 IN R5 MOV W.MAP(R1),KISAR5 ;POINT APR5 TO SECONDARY POOL WINDOW BEQ 20$ ;BRANCH ON NO MAP MOV #120000,R1 ;SET R1 TO MAP THRU APR5 .ENDC ;END SECONDARY POOL CONDITIONAL .IF DF D$$CHE ;DISK DATA CACHING SUPPORT CLR $DCCEL ;ASSUME THAT THIS MAP WILL FAIL .IFTF ;D$$CHE ADD #777,R0 ;ROUND BYTES TO NEXT 256. WORD BLOCK ROR R0 ;CONVERT TO WORDS CLRB R0 ;CLEAR RESIDUAL BITS SWAB R0 ;SWAP NUMBER OF BLOCKS TO LOW BYTE .IF DF,E$$LBN ;DC430 MOV W.VBN(R1),R4 ;GET HIGH ORDER WORD OF VBN ;DC430 .IFF ;DF,E$$LBN ;DC430 MOVB W.VBN(R1),R4 ;GET HIGH ORDER 7 BITS OF VBN ;DC430 .ENDC ;DF,E$$LBN ;DC430 SUB R4,R2 ;NORMALIZE HIGH PART OF VBN ;**-1 SUB W.VBN+2(R1),R3 ;NORMALIZE LOW PART TOO SBC R2 BLO 20$ ;BRANCH ON MAPPING FAILURE MOVB (R1),R4 ;GET NUMBER OF ACTIVE POINTERS BEQ 20$ ;BRANCH IF NONE - MAP FAILURE ADD #W.RTRV,R1 ;POINT R1 TO MAPPING POINTERS 10$: SUB (R1)+,R3 ;SUBTRACT EXTENT SIZE FROM VBN SBC R2 ;ALSO HIGH VBN BLO 30$ ;BRANCH IF VBN IN THIS EXTENT CMP (R1)+,(R1)+ ;INCREMENT PAST LBN SOB R4,10$ ;DECRIMENT POINTER COUNT & LOOP 20$: SEC ;INDICATE MAPPING FAILURE BR 70$ ;RETURN WITH CARRY SET - ERROR 30$: ADD R3,R0 ;TEST FOR ALL BLOCKS IN THIS EXTENT BGT 40$ ;BRANCH IF NOT - ONLY PARTIAL MAPPING CLR R0 ;INDICATE COMPLETE MAPPING 40$: ADD -2(R1),R3 ;R3 = OFFSET WITHIN EXTENT ADC R2 ;R2 = HIGH OFFSET (SHOULD BE 0) ADD (R1)+,R2 ;ADD THE BIGINNING LBN OF ADD (R1)+,R3 ;THE EXTENT TO THE OFFSET TO ADC R2 ;GET THE DESIRED LBN ;NOTE: AT THIS POINT CARRY IS CLEAR FOR SUCCESSFUL RETURN .IFT ;D$$CHE SUB #6,R1 ;BACKTRACK TO THE BEGINNING OF RTV MOV (R1)+,$DCCEL ;ASSUMPTION INCORRECT, SET CURRENT LENGTH MOV (R1)+,$DCCEB ;SET CURRENT EXTENT BASE LBN MOV (R1)+,$DCCEB+2 ;(DOUBLEWORD) CLR $DCNEL ;ASSUME NONEXISTENCE OF NEXT RTV DEC R4 ;OUR ASSUMPTION CORRECT? BEQ 50$ ;YES IF EQ; DON'T FILL IN NEXT RTV MOV (R1)+,$DCNEL ;ELSE SET NEXT EXTENT LENGTH MOV (R1)+,$DCNEB ;SET NEXT EXTENT BASE LBN MOV (R1)+,$DCNEB+2 ;(DOUBLEWORD) ;NOTE: CC BY 'CLR'S ABOVE, PRESERVED THROUGH HERE AS NEEDED 50$: .ENDC ;D$$CHE 70$: .IF DF P$$WND MOV R5,KISAR5 ;RESTORE SYSTEM APR5 .ENDC ;END SECONDARY POOL CONDITIONAL RETURN ;RETURN ;+ ; **-$LCKPR-LOCK PROCESSING ROUTINE ; ; THIS ROUTINE FIRST DETERMINES IF A FILE I/O REQUEST IS TO A SHARED ; FILE. IF SO, IT DETERMINES IF THE REQUEST IS AN UNLOCK QIO OR A ; VIRTUAL BLOCK I/O REQUEST. IT THEN EITHER PERFORMS THE UNLOCK QIO ; OR THE LOCK PROCESSING RESPECTIVELY. ; ; INPUTS: ; ; R1=I/O PACKET ADDRESS OF THE REQUEST ; ; OUTPUTS: ; ; C=0 IF NO LOCK PROCESSING WAS REQUIRED. ; ; C=1 IF AN UNLOCK WAS PERFORMED OR AN ERROR CONDITION OCCURED ; DURING THE LOCK PROCESSING. ; R0=I/O STATUS ; ; R1 IS PRESERVED. ;- .IF DF R$$LKL $LCKPR::MOV @I.LN2(R1),R3 ;POINT TO WINDOW BLOCK BIC #1,R3 ;CLEAR INTERLOCK BIT MOV #IE.ULK&377,R0 ;SET FOR UNLOCK ERROR STATUS MOV W.LKL(R3),R2 ;POINT TO FIRST ENTRY IN LOCK LIST BEQ 50$ ;IF EQ THERE IS NONE ; ; AT THIS POINT WE KNOW THAT BLOCK LOCKING IS ENABLED FOR THE FILE. ; ; THE TYPE OF LOCK REQUESTED IS EITHER SHARED OR EXCLUSIVE DEPENDING ; ON THE TYPE OF ACCESSOR AND THE I/O FUNCTION. ; ; IF REQUEST IS FROM A READER THEN I.FCN(R1) IS ; IO.RVB TO READ WITH SHARED LOCK ; IO.ULK TO UNLOCK ANY OR ALL EXISTING LOCKS ; IO.ULK!IQ.LCK TO REQUEST A SHARED LOCK WITHOUT ANY I/O ; ; IF THE REQUEST IS FROM A WRITER THEN I.FCN(R1) IS ; IO.RVB TO READ WITH AN EXCLUSIVE LOCK ; IO.RVB!IQ.LCK TO READ WITH A SHARED LOCK ; IO.WVB TO WRITE WITH EXCLUSIVE LOCK ; IO.ULK TO UNLOCK ANY OR ALL EXISTING LOCKS ; IO.ULK!IQ.LCK TO REQUEST A EXCLUSIVE LOCK WITHOUT I/O ; SAVNR ;SAVE R4 AND R5 MOV I.PRM+4(R1),R4 ;PICK UP BYTE COUNT FOR REQUEST ADD #777,R4 ;ROUND TO NEXT DISK BLOCK ROR R4 ;CONVERT TO SIZE IN BLOCKS CLRB R4 ; SWAB R4 ; CMPB I.FCN+1(R1),#IO.ULK/256. ;IS THIS AN UNLOCK REQUEST? BNE 100$ ;IF NE NO ; ASSUME IQ.LCK,200 TSTB I.FCN(R1) ;LOCK WITHOUT I/O REQUEST? BPL 5$ ;IF PL NO CALL 100$ ;DO LOCK PROCESSING DEC @I.PRM+16(R1) ;UNBUSY LOCK BLOCK SINCE NO I/O BR 50$ ;JOIN COMMON CODE 5$: ;REFERENCE LABEL ; ; UNLOCK PROCESSING ; ; THIS SECTION OF THE ROUTINE PERFORMS THE UNLOCK PROCESSING. RELEVANT ; REGISTER CONTENTS AT THIS POINT ARE: ; ; R0=UNLOCK ERROR STATUS ; R1=I/O PACKET ADDRESS ; R2=ADDRESS OF THE FIRST LOCK BLOCK IN THE LOCK LIST ; R3=POINTER TO CURRENT WINDOW ; R4=BYTE COUNT OF CURRENT UNLOCK REQUEST ; MOV I.PRM+12(R1),R5 ;CREATE BLOCK NUMBER SPECIFIED FLAG BISB I.PRM+10(R1),R5 ; 10$: TSTB L.CNT(R2) ;THIS LOCK BLOCK IN USE? BEQ 40$ ;IF EQ NO TST R5 ;BLOCK NUMBER SPECIFIED? BEQ 20$ ;IF EQ NO CALL 180$ ;EXACT VBN AND COUNT MATCH? BNE 40$ ;IF NE NO 20$: CMP L.WI1(R2),R3 ;SAME OWNER? BNE 40$ ;IF NE NO CLRB L.CNT(R2) ;UNLOCK THE LOCK MOV #IS.SUC&377,R0 ;SET FOR SUCCESSFUL RETURN TST R5 ;WAS THIS FOR AN EXPLICIT BLOCK NUMBER? BNE 50$ ;IF NE YES 40$: MOV (R2),R2 ;POINT TO NEXT LOCK BLOCK BNE 10$ ;IF NE THERE IS ONE ; ; NO LOCK LIST EXISTS ; ; IF THE FUNCTION IS NOT AN UNLOCK FUNCTION, A SIMPLE RETURN OCCURS ; WITH CARRY CLEAR. AN UNLOCK IN THIS CASE IS AN ERROR. (NOTE THAT ; ALL UNLOCK REQUESTS FALL THROUGH HERE AS WELL.) ; 50$: CMPB I.FCN+1(R1),#+1 ;SET CARRY IF UNLOCK RETURN ; ; ; LOCK PROCESSING ; ; THIS ROUTINE CHECKS FOR ATTEMPTED LOCK OVERLAPS, ATTEMPTS TO SET THE ; NEW LOCK, AND PERFORMS THE IMPLIED UNLOCK. IF A NEW LOCK REQUEST ; FOR AN EXPLICIT UNLOCKER IS DETECTED WHICH EXACTLY MATCHES AN EXISTING ; LOCK FOR THAT WINDOW IN BOTH STARTING VBN AND SIZE, THE LOCK BLOCK IS ; SIMPLY REUSED. RELEVANT REGISTER CONTENTS AT THIS POINT ARE: ; ; R1=I/O PACKET ADDRESS ; R2=ADDRESS OF FIRST LOCK BLOCK IN LOCK LIST ; R3=ADDRESS OF FILE WINDOW ; R4=BLOCK COUNT FOR CURRENT REQUEST ; ; ; THE FOLLOWING CASES ARE CONSIDERED: ; ; 1. IF THE REQUEST IS FOR A WINDOW WITH IMPLICIT (NOT EXPLICIT, ; WI.EXL) UNLOCKING AND THERE EXISTS A CURRENT LOCK FOR THAT ; WINDOW WITH I/O STILL IN PROGRESS THEN RETURN A LOCK ERROR ; (IE.LCK). ; ; 2. IF THE REQUEST IS AN EXACT MATCH FOR A LOCK WHICH IS AN ; EXACT MATCH OF WINDOW (OWNER), LBN, AND SIZE AND WHICH ; HAS I/O STILL IN PROGRESS THEN RETURN A LOCK ERROR (IE.LCK). ; ; 3. IF THE REQUEST IS FROM A WINDOW WITH ONLY READ ACCESS OR A ; READ REQUEST REQUESTING ONLY SHARED ACCESS FROM A WRITER ; ATTEMPT TO GRANT A SHARED LOCK. IF THERE IS NO EXISTING ; LOCK WITH OVERLAP THEN GRANT THE SHARED LOCK. IN THE CASE ; OF A CONFLICT SEE TABLE BELOW. ; ; 4. IF THE REQUEST IS FROM A WINDOW WITH WRITE ACCESS AND IS A ; WRITE OR A READ WITHOUT A SHARED LOCK REQUEST ATTEMPT TO ; GRANT AN EXCLUSIVE LOCK. IF THERE IS NO EXISTING LOCK WITH ; OVERLAP THEN GRANT AN EXCLUSIVE LOCK. IN THE CASE OF CONFLICT ; SEE TABLE BELOW. ; ; 5. DECISION TABLE FOR RESOLVING CONFLICTS: ; ; I/O REQUEST ; LOCK SHARED EXCLUSIVE ; ; EXACT MATCH GRANT SHARED GRANTED EXCLUSIVE ; IF NO OTHER CONFLICT ; (REUSE LOCK BLOCK) (REUSE LOCK BLOCK) ; ; CONFLICT SHARED GRANT SHARED REJECT IE.LCK ; ; CONFLICT EXCLUSIVE REJECT IE.LCK REJECT IE.LCK ; 100$: CLR R5 ;INIT FREE NODE POINTER MOV #IE.LCK&377,-(SP) ;PUSH LOCK ERROR STATUS CLR -(SP) ;ASSUME SHARED LOCK BIT #WI.WRV,(R3) ;IS THIS REQUEST FOR A WRITER? BEQ 110$ ;IF EQ NO, ALWAYS SHARED LOCK CMPB I.FCN+1(R1),#IO.RVB/400 ; IS THIS A READ REQUEST? BNE 105$ ;IF NE NO, ALWAYS EXCLUSIVE LOCK ; ASSUME IQ.LCK,200 TSTB I.FCN(R1) ;SHARED LOCK REQUESTED? BMI 110$ ;IF MI YES 105$: INC (SP) ;SET EXCLUSIVE LOCK REQUESTED 110$: TSTB L.CNT(R2) ;IS LOCK BLOCK IN USE? BNE 120$ ;IF NE YES TST R5 ;ALREADY HAVE FREE BLOCK? BNE 150$ ;IF NE YES, LOOK AT NEXT LOCK BLOCK BR 130$ ;ELSE CLAIM THIS BLOCK 120$: MOV L.WI1(R2),R0 ;PICK UP OWNER WORD BIC #1,R0 ;CLEAR BIT FOR NO UNLOCK FLAG CMP R0,R3 ;LOCK BELONG TO THIS WINDOW? BNE 140$ ;IF NE NO, CHECK FOR OVERLAPS BIT #WI.EXL,(R3) ;EXPLICIT UNLOCKER? BEQ 125$ ;IF EQ NO, SAVE BLOCK FOR IMPLIED UNLOCK CALL 180$ ;EXACT VBN AND COUNT? BNE 140$ ;IF NE NO 125$: MOV L.WI1(R2),R0 ;RETRIEVE OWNER WORD ROR R0 ;CAN LOCK BLOCK BE REUSED? BCS 153$ ;IF CS NO 130$: MOV R2,R5 ;SET TO REUSE THIS LOCK BLOCK BR 150$ ;LOOK AT NEXT LOCK BLOCK 140$: MOVB L.CNT(R2),R0 ;PICKUP LOCK BLOCK COUNT, EXCLUSIVE? BMI 141$ ;IF MI YES TST (SP) ;REQUEST EXCLUSIVE LOCK? BEQ 150$ ;IF NE NO BR 142$ ;DO CONFLICT CHECK 141$: NEG R0 ;CONVERT TO MAGNITUDE 142$: ADD L.VB1+2(R2),R0 ;CALCULATE NUMBER OF HIGHEST BLOCK + 1 MOVB L.VB1(R2),-(SP) ;PUSH HIGH ORDER BYTE ADCB (SP) ;PROPAGATE CARRY CMPB I.PRM+10(R1),(SP)+ ;OVERLAP? BNE 145$ ;IF NE USE BRANCH BELOW CMP I.PRM+12(R1),R0 ;OVERLAP? 145$: BHIS 150$ ;IF HIS NO MOV R4,R0 ;COPY SIZE OF CURRENT REQUEST ADD I.PRM+12(R1),R0 ;CALCULATE NUMBER OF HIGHEST BLOCK +1 MOVB I.PRM+10(R1),-(SP) ;PUSH HIGH ORDER BYTE ADCB (SP) ;PROPAGATE CARRY CMPB L.VB1(R2),(SP)+ ;OVERLAP? BNE 146$ ;IF NE USE BRANCH BELOW CMP L.VB1+2(R2),R0 ;OVERLAP? 146$: BLO 153$ ;IF LO YES, (CARRY SET) 150$: MOV (R2),R2 ;POINT TO NEXT LOCK BLOCK BNE 110$ ;IF NE THERE IS ONE ; ; HACK: IN ORDER TO PHASE IN REAL READER LOCKS WHICH ARE NOT SUPPORTED ; BY RMS-11 V1.8, THE FOLLOWING CODE IS INCLUDED TO PREVENT THEM FROM ; BEING CREATED. AT SOME FUTURE TIME THIS CODE WILL BE REMOVED. ; .IF NE 1 BIT #WI.WRV,(R3) ;READER? BEQ 170$ ;IF EQ YES .ENDC MOV R5,R0 ;COPY POINTER TO SAVED LOCK BLOCK BNE 160$ ;IF NE ONE WAS IN FACT SAVED MOV #IE.NOD&377,2(SP) ;ASSUME ALLOCATION FAILURE STATUS MOV R1,-(SP) ;SAVE I/O PACKET ADDRESS MOV #L.LKSZ,R1 ;PICKUP SIZE OF LOCK BLOCK CALL $ALOCB ;ALLOCATE LOCK BLOCK MOV (SP)+,R1 ;RESTORE I/O PACKET ADDRESS BCC 155$ ;IF CC SUCCESS 153$: ROL (SP) ;SAVE CARRY BR 170$ ;JOIN COMMON EXIT CODE 155$: MOV @W.LKL(R3),(R0) ;POINT NEW BLOCK TO SECOND IN LIST MOV R0,@W.LKL(R3) ;POINT FIRST BLOCK IN LIST TO NEW ONE 160$: TST (R0)+ ;ADVANCE TO OWNER WORD MOV R0,I.PRM+16(R1) ;SAVE POINTER TO OWNER WORD MOV R3,(R0) ;SET OWNER WORD INC (R0)+ ;SET NO UNLOCK FLAG MOVB I.PRM+10(R1),(R0)+ ;SET HIGH PART OF VBN ROR (SP) ;EXCLUSIVE LOCK? BCC 165$ ;IF CC NO NEG R4 ;SET FOR EXCLUSVE LOCK 165$: MOVB R4,(R0)+ ;SET BLOCK COUNT MOV I.PRM+12(R1),(R0) ;SET LOW PART OF VBN MOV #IS.SUC&377,2(SP) ;SET SUCCESS FOR LOCK WITHOUT I/O CASE 170$: ROR (SP)+ ;SET CARRY, CLEAN STACK MOV (SP)+,R0 ;PICKUP ERROR STATUS RETURN ; ; ; ROUTINE TO CHECK FOR EXACT VBN AND BLOCK COUNT MATCH ; ; INPUTS: ; ; R1=I/O PACKET ADDRESS ; R2=LOCK BLOCK ADDRESS ; R4=BYTE COUNT ; ; OUTPUTS: ; ; ALL REGISTERS PRESERVED. ; ; Z=1 IF EXACT MATCH. ; ; Z=0 IT NO MATCH. ; 180$: CMP L.VB1+2(R2),I.PRM+12(R1) ;MATCH ON LOW ORDER? BNE 190$ ;IF NE NO CMPB L.VB1(R2),I.PRM+10(R1) ;MATCH ON HIGH ORDER? BNE 190$ ;IF NE NO TST R4 ;COUNT SPECIFIED? BEQ 190$ ;IF EQ NO MOVB L.CNT(R2),-(SP) ;GET LOCK BLOCK COUNT, NEGATIVE? BPL 185$ ;IF PL NO NEGB (SP) ;COMPUTE MAGNITUDE 185$: CMPB (SP)+,R4 ;CLEAN STACK, MATCH ON COUNT? 190$: RETURN ; .ENDC ;+ ; **-$RQCNC-REQUEST CONTROLLER FOR CONTROL OPERATIONS ; ; THIS ROUTINE IS CALLED TO REQUEST CONTROL FUNCTION ACCESS TO A ; CONTROLLER THAT SUPPORTS OVERLAPPED CONTROL OPERATIONS. ACCESS IS ; GRANTED TO A SPECIFIC UNIT. IF THE UNIT IS MULTI-ACCESS, CONTROLLER ; ASSIGNMENT IS PERFORMED FOR IT. IF THE CONTROLLER IS BUSY, THE DRIVER ; PROCESS CONTEXT IS STORED IN THE FORK BLOCK, AND IT IS QUEUED ON THE ; CONTROLLER REQUEST QUEUE FOR THAT CONTROLLER. IF THE DRIVER IS NOT ; BUSY, A $CFORK IS PERFORMED TO ENSURE EXECUTION ON THE CORRECT CPU, ; AND A RETURN TO THE CALLER IS EXECUTED. ; ; INPUTS: ; ; R4=SCB ADDRESS. ; R5=UCB ADDRESS OF REQUESTING UNIT. ; 0(SP)=DRIVERS RETURN ADDRESS. ; 2(SP)=RETURN ADDRESS OF DRIVERS CALLER. ; ; OUTPUTS: ; ; R4=SCB ADDRESS. ; R5=UCB ADDRESS OF REQUESTING UNIT. ; ; S.FRK+2 IS ALWAYS NON-ZERO. ; ; ACCESS IS GRANTED TO THE CONTROLLER FOR CONTROL FUNCTIONS ONLY. ; ; R4 AND R5 ARE PRESERVED ACROSS CALL. ;- .ENABL LSB .IF DF O$$LAP $RQCNC::MOV R4,R1 ;GET SCB ADDRESS IN PROPER REG FOR QUEUE MOV S.KRB(R4),R0 ;GET KRB ADDRESS INC S.FRK+2(R4) ;MAKE SURE THAT S.FRK+2 <> 0 CMP R5,K.OWN(R0) ;ARE WE OWNER? BEQ 180$ ;IF EQ YES -- RETURN .IF DF M$$ACD CALL ASKRB .ENDC BIT #KS.SDX,K.STS(R0) ;SEEKS DURING DATA XFERS SUPPORTED? BEQ 100$ ;IF EQ NO .IF DF M$$PRO CALLR $CFORK ;ASSURE EXECUTION ON CORRECT PROCESSOR .IFF RETURN ;RETURN TO DRIVER WITH ACCESS GRANTED .ENDC 100$: MOV (SP)+,R4 ;SAVE DRIVER RETURN ADDRESS TST K.OWN(R0) ;IS CONTROLLER BUSY .IF DF M$$PRO BNE 150$ ;IF NE YES CALL $CFORK ;NOT BUSY - TRANSFER TO CORRECT CPU MOV U.SCB(R5),R1 ;GET BACK SCB ADDRESS MOV S.KRB(R1),R0 ;GET BACK KRB ADDRESS TST K.OWN(R0) ;IS IT BUSY NOW? .ENDC BEQ 300$ ;IF EQ NO -- GRAB IT FOR OURSELVES 150$: MOV #$QINSB,-(SP) ;SAVE QUEUEING ROUTINE ADDRESS BR 350$ ;SAVE DRIVER CONTEXT AND EXIT .ENDC ; DF O$$LAP ;+ ; **-$RQCND-REQUEXT CONTROLLER FOR DATA TRANSFER ; ; THIS ROUTINE IS CALLED FOR ACCESS TO A CONTROLLER FOR AN OPERATION ; THAT WILL BUSY OUT THE CONTROLLER, USUALLY A DATA TRANSFER. IF THE ; UNIT IS MULTI-ACCESS, CONTROLLER ASSIGNMENT IS PERFORMED. $CFORK IS ; USED IF NECESSARY TO ENSURE EXECUTION ON THE CORRECT PROCESSOR. ; ; NOTE: IF THE SCB IS ALREADY IN A CONTROLLER REQUEST QUEUE, WE ; SKIP THE CALL AND RETURN TO THE CALLER'S CALLER. THIS IS ; BELIEVED TO HAPPEN ONLY ON NON-DEC SUPPLIED DM: TYPE DISKS ; DURING POWERFAIL RECOVERY. NOTE THAT THIS BASICALLY ; DISMISSES THE DRIVERS POWER RECOVERY CALL. WE HOPE THAT THE ; DRIVER KNOWS HOW TO RECOVER WHEN ITS OTHER $RQCND CALL ; COMPLETES. ; ; INPUTS: ; ; R5=ADDRESS OF REQUESTING UNITS UCB ; 0(SP)=DRIVER RETURN ADDRESS ; 2(SP)=RETURN ADDRESS OF DRIVERS CALLER ; ; OUTPUTS: ; ; R4=SCB ADDRESS. ; R5=UCB ADDRESS OF REQUESTING UNIT. ; ; S.FRK+2 IS ALWAYS NON-ZERO. ; ; ; DRIVER HAS EXCLUSIVE ACCESS TO CONTROLLER. ; ;- $RQCND::MOV U.SCB(R5),R1 ;GET SCB ADDRESS .IF DF S2.NRD BIT #S2.KRQ,S.ST2(R1) ;KRB ALREADY IN REQUEST QUEUE? BNE 370$ ;IF NE YES, IGNORE THIS CALL .ENDC ; DF S2.NRD MOV S.KRB(R1),R0 ;GET KRB ADDRESS CMP R5,K.OWN(R0) ;IS REQUESTING UNIT ALREADY THE OWNER? BNE 190$ ;IF NE NO, MAKE HIM THE OWNER MOV R1,R4 ;PUT SCB IN CORRECT PLACE 180$: INC S.FRK+2(R4) ;ALWAYS EXIT WITH S.FRK+2 <> 0 RETURN 190$: ;REFERENCE LABEL .IF DF M$$ACD CALL ASKRB .ENDC INCB K.IOC(R0) ;COUNT AN I/O REQUEST ON THIS KRB MOV (SP)+,R4 ;PUT DRIVER RETURN ADDRESS IN R4 TST K.OWN(R0) ;IS CONTROLLER BUSY? .IF DF M$$PRO BNE 340$ ;IF NE YES CALL $CFORK ;TRANSFER TO CORRECT PROCESSOR MOV U.SCB(R5),R1 ;GET SCB ADDRESS BACK MOV S.KRB(R1),R0 ;GET KRB ADDRESS BACK TST K.OWN(R0) ;IS IT BUSY .ENDC BNE 340$ ;IF NE YES ; ; SET OWNER AND RETURN ; 300$: MOV R5,K.OWN(R0) ;SET OWNER MOV R4,R0 ;SAVE RETURN ADDRESS MOV R1,R4 ;PUT SCB ADDRESS IN CORRECT PLACE INC S.FRK+2(R4) ;ALWAYS EXIT WITH S.FRK+2 <> 0 JMP (R0) ;RETURN TO CALLING DRIVER 340$: MOV #$QINSF,-(SP) ;SET QUEUEING ADDRESS BIS #S2.KRQ,S.ST2(R1) ;INDICATE REQUEST IS IN QUEUE ; ; STORE DRIVER CONTEXT IN FORK BLOCK AND RETURN TO DRIVERS CALLER ; 350$: MOV R1,S.FRK+6(R1) ;SAVE SCB IN R4 SAVE AREA ADD #S.FRK+6,R1 ;POINT TO R5 SAVE AREA + 2 MOV R5,-(R1) ;SAVE R5 MOV R4,-(R1) ;SAVE DRIVERS RETURN ADDRESS CLR -(R1) ;CLEAR LINK WORD ADD #K.CRQ,R0 ;POINT TO QUEUE FOR DRIVERS 360$: RETURN ;EXIT TO PROPER QUEUEING ROUTINE 370$: TST (SP)+ ;REMOVE CALLER'S ADDRESS RETURN ;RETURN TO CALLER'S CALLER ;+ ; **-$RLCN-RELEASE CONTROLLER ; ; THIS ROUTINE WILL RELEASE THE CONTROLLER IF THE CALLER IS THE OWNER ; OF THE CONTROLLER. IT WILL ALSO PLACE THE FORK BLOCK FOR THE NEXT ; DRIVER (IF ANY) IN THE CONTROLLER WAIT QUEUE INTO THE FORK QUEUE ; AFTER MAKING THAT DRIVER THE OWNER OF THE CONTROLLER. IF THE DRIVER ; IS NOT THE OWNER, A RETURN IS EXECUTED. ; ; INPUTS: ; ; R4=SCB ADDRESS. ; R5=UCB ADDRESS OF UNIT THAT IS RELEASING CONTROLLER. ; ; OUTPUTS: ; ; CONTROLLER IS RELEASED. ; ; ALL REGISTERS EXECEPT R3 ARE PRESERVED. ;- $RLCN:: MOV S.KRB(R4),R3 ;GET KRB ADDRESS CMP R5,K.OWN(R3) ;IS RELEASING UNIT OWNER BNE 460$ ;IF NE NO, RETURN CLR K.OWN(R3) ;CLEAR OUT OWNER OF CONTROLLER ADD #K.CRQ,R3 ;POINT TO CONTROLLER RQST QUEUE DECB K.IOC-K.CRQ(R3) ;COUNT ONE LESS I/O ON THIS KRB MOV (R3),R4 ;GET NEXT EXTRY BEQ 450$ ;IF EQ NO DRIVER IS WAITING -- RETURN MOV (R4),(R3) ;SET NEW FIRST IN LIST BNE 400$ ;IF NE OLD LAST IS STILL LAST MOV R3,2(R3) ;SET NEW LAST -- EMPTY LIST 400$: MOV 4(R4),K.OWN-K.CRQ(R3) ;SET NEW OWNER WITH R5 FROM FORK CLR (R4) ;CLEAR FORK LINK WORD CALL $QFORK ;INSERT FORK BLOCK INTO FORK QUEUE 450$: MOV U.SCB(R5),R4 ;REPLACE SCB IN R4 BIC #S2.KRQ,S.ST2(R4) ;SCB IS NOT IN QUEUE 460$: RETURN ; .DSABL LSB ; ; **-ASKRB-ASSIGN KRB FOR DUAL-ACCESS DEVICE ; ; THIS ROUTINE WILL PROPERLY ASSIGN THE KRB FOR A DUAL-ACCESS DEVICE ; THAT USES KS.UOP SYNCRONIZATION. ; ; INPUTS: ; ; R0=CURRENTLY ASSIGNED KRB ADDRESS. ; R1=SCB ADDRESS FOR DUAL-ACCESS DEVICE. ; ; OUTPUTS: ; ; R0=KRB ADDRESS FOR KRB OF CHOICE. ; R1=SCB ADDRESS FOR DUAL-ACCESS DEVICE. ; ; REGISTERS R2 AND R3 ARE DESTROYED ; .IF DF M$$ACD ASKRB: MOV #S2.MAD!S2.LDS,R2 ;GET STATUS BITS BIC S.ST2(R1),R2 ;ARE ALL OF THE ABOVE BITS SET BNE 30$ ;IF NE NO -- EXIT NOW BITB #S3.DRL,S.ST3(R1) ;IS THE DRIVE RELEASED? BEQ 30$ ;IF NE NO -- EXIT NOW ; ; GET PORT A KRB -- CHECK IT OUT ; MOV S.KTB(R1),R2 ;GET PORT A KRB ADDRESS BIC #KP.OFL,R2 ;CLEAR OUT LOW ORDER BIT MOV S.KTB+2(R1),R3 ;GET PORT B KRB ADDRESS BIC #KP.OFL,R3 ;CLEAR OUT LOW ORDER BIT ; ; GET PORT A -- CHECK IT FOR OFFLINE ; BIT #KS.OFL,K.STS(R2) ;IS THE KRB OFFLINE BNE 10$ ;IF NE YES, SELECT PORT B ; ; GET PORT B KRB -- CHECK IT OUT ; BIT #KS.OFL,K.STS(R3) ;IS KRB ONLINE? BNE 20$ ;IF NE NO, SELECT PORT A ; ; BOTH KRB'S ARE ONLINE -- NOW CHECK FOR PORT RELATIVE I/O ; MOV S.PKT(R1),R0 ;GET I/O PACKET ADDRESS MOV I.FCN(R0),-(SP) ;GET I/O FUNCTION FROM PACKET BIC #7,(SP) ;REMOVE QUALIFIER BITS (SEE $VOLVD) CMP #IO.STC,(SP)+ ;IS IT IO.STC FUNCTION? BEQ 40$ ;IF EQ YES ; ; BOTH KRB'S ARE ONLINE, IT IS NOT PORT RELATIVE I/O FUNCTION. ; NOW CHECK FOR THE PDF AND PORT SPECIFIC OFFLINE BITS. ; 5$: BIT #KP.OFL,S.KTB(R1) ;IS PORT A OFL FROM THIS UNIT BNE 10$ ;IF NE YES -- SELECT PORT A BIT #KP.OFL,S.KTB+2(R1) ;IS PORT B OFL FROM THIS UNIT BNE 20$ ;IF NE YES -- SELECT PORT B ; ; NOW THE PDF BITS (WHICH, FOR NON PORT-SPECIFIC I/O, ARE EQU TO OFL). ; BIT #KS.PDF,K.STS(R2) ;IS PORT A PDF SET? BNE 10$ ;IF NE YES -- SELECT PORT B BIT #KS.PDF,K.STS(R3) ;IS PORT B PDF SET? BNE 20$ ;IF NE YES -- SELECT PORT A ; ; AT THIS POINT, BOTH KRB'S ARE EQUIVALENT FROM THE STANDPOINT ; OF BEING EQUALLY ONLINE, AND THIS WASN'T PORT SPECIFIC I/O. ; ; NOW WE WILL COMPARE THE KRB'S TO SEE WHICH IS BUSIER. IF THEY ; ARE THE SAME, THEN WE WILL SEE IF ONE IS ATTACHED TO THIS CPU. ; IF IT IS, THEN WE WILL USE IT. ; CMPB K.IOC(R2),K.IOC(R3) BLO 20$ ;IF LO PORT A IS FREER BHI 10$ ;IF HI PORT B IS FREER .IF DF M$$PRO BIT @$CPURM,K.URM(R2) ;CAN WE GET TO ONE EASIER THAN THE OTHER? BNE 20$ ;IF NE YES -- PORT A .ENDC 10$: MOV R3,R2 ;SELECT PORT B 20$: MOV R2,S.KRB(R1) ;SET KRB ADDRESS MOV R2,R0 ;SHOW KRB OF CHOICE .IF DF M$$PRO MOV K.URM(R0),S.URM(R1) ;SET URM IN FORK BLOCK OF SCB .ENDC 30$: BICB #S3.DRL,S.ST3(R1) ;SHOW CONTROLLER ASSIGNED RETURN ; ; FUNCTION IS IO.STC, SEE IF PORT SPECIFICATION EXISTS. IF IT ; DOES, THEN SWITCH TO SPECIFIED PORT. ; 40$: MOVB I.PRM+4(R0),R0 ;GET PORT SPECIFICATION BEQ 5$ ;IF EQ NONE EXISTS SUB #1,R0 ;IS IT PORT A BNE 10$ ;IF NE NO BR 20$ ;IF EQ YES .ENDC ;+ ; **-$ECCOR-ECC CORRECTION ROUTINE ; ; THIS ROUTINE WILL TAKE THE 22 BIT REAL STARTING ADDRESS OF THE ; TRANSFER, CALCULATE WHERE THE ECC CORRECTION SHOULD TAKE PLACE, AND ; PERFORM THE ACTUAL XOR OPERATION TO CORRECT THE DATA IN MEMORY. ; ; INPUTS: ; ; R0=BYTES ACTUALLY TRANSFERED ; R1=ECC ERROR POSITION (FROM HARDWARE REGISTER) ; R3=ECC ERROR CORRECTION PATTERN (FROM HARDWARE REGISTER) ; R4=SCB ADDRESS ; R5=UCB ADDRESS ; ; OUTPUTS: ; ; R2=CSR ADDRESS ; R3=CONTROLLER INDEX ; ; R0, R4, R5 ARE PRESERVED ;- .IF DF S$$ECC $ECCOR::MOV R4,-(SP) ;SAVE SCB ADDRESS MOV R0,-(SP) ;SAVE NUMBER OF BYTES TRANSFERED CLR R0 ;CLEAR HIGH ORDER ERROR POSITION DEC R1 ;MAKE POSITION INTO 0-7777 RANGE DIV #20,R0 ;DIVIDE FOR: ; R0=WORD POSITION (0-377) ; R1=BIT POSITION (0-17) MOV R0,-(SP) ;SAVE WORD POSITION CLR R2 ;CLEAR HIGH ORDER ERROR PATTERN ASHC R1,R2 ;SHIFT PATTERN INTO CORRECT POSITION MOV U.BUF+2(R5),R1 ;GET LOW 16 BITS OF ADDRESS MOVB U.BUF+1(R5),R0 ;GET HIGH BITS OF REAL ADDRESS MOV S.KRB(R4),R4 ;RETREIVE KRB ADDRESS BIT #KS.MBC,K.STS(R4) ;IS THIS A 22-BIT MASSBUS DEVICE? BNE 10$ ;IF NE YES ADD K.OFF(R4),R4 ;POINT TO UMR AREA+2 MOV -(R4),R1 ;GET LOW 16 BITS OF REAL ADDRESS MOVB -(R4),R0 ;GET HIGH 6 BITS OF REAL ADDRESS 10$: MOV 2(SP),R4 ;GET BYTES ACTUALLY TRANSFERED BIC #777,R4 ;GET NUMBER OF FULL BLOCKS TRANSFERED BEQ 15$ ;IF EQ THERE WERE NONE SUB #512.,R4 ;BACKUP TO BLOCK IN ERROR 15$: ADD R4,R1 ;CALCULATE STARTING ADDRESS OF BAD BLOCK ADC R0 ;... ASHC #10.,R0 ;CALCULATE DISPLACEMENT AND BIAS ASHC #-10.,R1 ;... MOV R0,KISAR6 ;SET RELOCATION BIAS ADD #140000+2,R1 ;POINT TO HIGH ORDER CORRECTABLE WORD MOV (SP)+,R4 ;GET WORD POSITION ADD R4,R1 ;ADD IN ERROR WORD POSITION OFFSET ... ADD R4,R1 ;... FOR BYTE ADDRESSING MOV (SP),R0 ;GET BYTES ACTUALLY TRANSFERED ASR R0 ;CONVERT TO WORDS BIC #^C<377>,R0 ;GET HIGHEST WORD TO CORRECT BNE 17$ ;IF NE, IT'S A PARTIAL WORD TRANSFER MOV #377,R0 ;SET R0 EQUAL TO VERY LAST WORD IN BLOCK 17$: CMP R4,R0 ;IS THE OFFSET WITHIN THE LIMIT? BHI 40$ ;IF HI NOT AT ALL BEQ 30$ ;IF EQ THEN ONLY ONE WORD IS 20$: XOR R2,(R1) ;CORRECT THE HIGH ORDER WORD 30$: XOR R3,-(R1) ;CORRECT THE LOW ORDER WORD 40$: MOV (SP)+,R0 ;RESTORE BYTES TRANSFERED MOV (SP)+,R4 ;RESTORE SCB ADDRESS MOV S.KRB(R4),R3 ;RETREIVE KRB ADDRESS MOV (R3),R2 ;RETREIVE CSR ADDRESS MOVB K.CON(R3),R3 ;RETREIVE CONTROLLER INDEX RETURN ; .ENDC ; DF S$$ECC ;+ ; **-$CRPAS - COMMON REGISTER PASS ROUTINE ; ; THIS SUBROUTINE IS USED TO PASS THE CONTENTS OF THE DEVICE REGISTERS ; BACK TO THE DIAGNOSTIC TASK. ALL REGISTERS ARE PASSED IN THE ORDER ; IN WHICH THEY APPEAR ON THE UNIBUS. ; ; NOTE: THIS ROUTINE MAKES USE OF THE ERROR LOGGING ENTRIES S.ROFF AND ; S.RCNT IN THE SCB. ; ; INPUTS: ; ; R1=I/O PACKET ADDRESS ; R2=CSR ADDRESS ; R4=SCB ADDRESS ; ; OUTPUTS: ; ; R1=DESTROYED. ; R0,R2 ARE PRESERVED ;- .IF DF U$$UMD $CRPAS::MOV R0,-(SP) ;SAVE R0 MOV I.PRM+14(R1),KISAR6 ;SET RELOCATION BIAS MOV I.PRM+16(R1),R0 ;GET REGISTER BUFFER ADDRESS MOV R2,-(SP) ;PRESERVE INITIAL CSR ADDRESS MOVB S.ROFF(R4),R2 ;GET OFFSET TO FIRST REGISTER ADD (SP),R2 ;ADD CSR ADDRESS MOVB S.RCNT(R4),R1 ;GET NUMBER OF REGISTERS TO XFER 10$: MOV (R2)+,(R0)+ ;TRANSFER A REGISTER SOB R1,10$ ;LOOP FOR ALL REGISTERS .IF DF M$$EXT MOV S.KRB(R4),R1 ;RETREIVE KRB ADDRESS BIT #KS.MBC,K.STS(R1) ;IS THIS A MASSBUS DEVICE? BEQ 20$ ;IF EQ NO ADD K.OFF(R1),R1 ;POINT TO UCB TABLE MOV -(R1),R1 ;RETREIVE RHBAE OFFSET ADD (SP),R1 ;FORM AN I/O PAGE ADDRESS MOV (R1)+,(R0)+ ;TRANSFER RHBAE MOV (R1),(R0) ;TRANSFER RHCS3 .ENDC 20$: MOV (SP)+,R2 ;RESTORE CSR ADDRESS MOV (SP)+,R0 ;RESTORE R0 RETURN .ENDC ; DF U$$UMD ;+ ; **-$VOLVD-PREPROCESS VOLUME VALID FUNCTION ; ; THIS ROUTINE PREPROCESSES ALL I/O FUNCTIONS TO SCREEN AND HANDLE ; VOLUME VALID REQUESTS. DISK DRIVERS CALL THIS ROUTINE AT THE START ; OF EACH OPERATION. THE ROUTINE WILL RETURN AN INDICATION OF WHICH OF ; THREE OUTCOMES THE DRIVER SHOULD TAKE: ; ; 1. NOP (SUCCESSFULLY COMPLETE) THE I/O, BECAUSE IT WAS A VOLUME ; VALID REQUEST HANDLED BY $VOLVD. ; 2. CONTINUE WITH THE I/O REQUEST, BECAUSE IT WAS NOT A VOLUME ; VALID REQUEST, AND NEEDS REAL DRIVER SERVICE. ; 3. RETURN AN ERROR, BECAUSE $VOLVD DETECTED A BAD VOLUME VALID ; QIO OR A TRANSFER TO A VOLUME WITH VOLUME VALID NOT SET. ; ; A VOLUME VALID I/O IS ONE WITH A FUNCTION CODE OF IO.STC, I.PRM = 0, ; AND I.PRM+2 IS A SUBFUNCTION CODE FOR WHICH VOLUME VALID FUNCTION (SEE BELOW) ; ; SPECIAL NOTE REGARDING THE INTERACTION OF DATA CACHEING SUBFUNCTION: ; ; THE IO.STC SUBFUNCTION CODE VV$CHE SHOULD BE CONSIDERED ; AN INVALID FUNCTION (AND CURRENTLY IS) IF RECEIVED BY ; $VOLVD. THIS SUBFUNCTION CODE IS INTERCEPTED, PROCESSED, ; AND TERMINATED BY THE CACHER. THESE OPERATIONS WILL ONLY ; REACH THE DRIVER IF DISK DATA CACHING IS NOT SUPPORTED IN ; THE CURRENTLY RUNNING EXECUTIVE, AND THOSE PACKETS SHOULD ; BE TERMINATED WITH STATUS IE.BAD. ; ; INPUTS: ; ; R1 = I/O PACKET ADDRESS ; ; I.PRM = ALWAYS ZERO ; I.PRM+2 = VOLUME VALID FUNCTION TYPE CODE: ; VV$SIZ -1 SIZE THE DRIVE (NO CHANGE IN VV) ; VV$SET 1 SET VOLUME VALID ; VV$UNL 2 UNLOAD THE DRIVE (CLEAR VV) ; VV$CHE 4 "DATA CACHE LOCAL" OPERATIONS ; 0 TO RESET VOLUME VALID BIT ; 1 TO SET VOLUME VALID BIT ; 2 TO RESET VOLUME VALID AND SPIN DRIVE DOWN ; 3 TO SET VOLUME VALID AND SPIN DRIVE UP ; 4 FOR "DATA CACHE LOCAL" OPERATIONS ; -1 TO SIZE THE DISK (VOLUME VALID NOT CHANGED) ; I.PRM+4 = RESERVED FOR PORT SPECIFICATION ; ; R5 = UCB ADDRESS ; ; OUTPUTS: ; ; C = 0 THEN THE FUNCTION CODE WAS IO.STC, AND THE FUNCTION WAS ; PROPERLY HANDLED, OR THE FUNCTION WAS A TRANSFER FUNCTION ; AND VOLUME VALID IS SET FOR THE VOLUME. REGISTERS AND CCS: ; ; R0 = IS.SUC&377 IF VOLUME VALID FUNCTION (IO.STC). ; R0 = -1 IF TRANSFER FUNCTION. ; N = 1 IF TRANSFER FUNCTION (R0 TESTED) ; ; C = 1 THEN THE FUNCTION WAS EITHER AN INVALID IO.STC, OR A TRANSFER ; FUNCTION TO A VOLUME WITHOUT VOLUME VALID SET. REGISTERS: ; ; R0 = I/O ERROR CODE. ;- VV$SIZ == -1 ; SIZE THE DRIVE VV$SET == 1 ; SET/CLEAR VOLUME VALID VV$UNL == 2 ; LOAD/UNLOAD THE DRIVE VV$CHE == 4 ; CACHE SUBFUNCTION OF IO.STC ; FIRST CHECK TO SEE IF THIS IS A ; VOLUME VALID FUNCTION $VOLVD::MOV #IE.IFC&377,R0 ; ASSUME ILLEGAL FUNCTION CODE MOV I.FCN(R1),-(SP) ; GET THE FUNCTION CODE BIC #7,(SP) ; REMOVE ANY QUALIFIER BITS CMP #IO.STC,(SP)+ ; VOLUME VALID FUNCTION? BNE 30$ ; IF NE NO ; YES, IT'S AN IO.STC. CHECK PRIVILIEGES. A ; PRIVILEGED TASK (LIKE MOUNT) CAN DO WHATEVER ; IT PLEASES. A NON-PRIVILEGED TASK CAN ONLY ; RESET VOLUME VALID ON A FOREIGN MOUNTED VOLUME. MOV I.TCB(R1),R0 ; GET TASKS TCB ADDRESS BIT #T3.PRV,T.ST3(R0) ; IS THE REQUESTING TASK PRIVILEGED? BNE 99$ ; IF NE YES BITB #US.FOR,U.STS(R5) ; VOLUME MOUNTED FOREIGN? BEQ 50$ ; IF EQ NO, CAN'T RESET ; IF VOLUME VALID IS ALREADY SET, THEN THE VOLUME ; NEEDN'T BE MOUNTED. THIS COVERS THE CASE OF A ; VOLUME DISMOUNTED WITH /LOCK=V 99$: BITB #US.VV,U.STS(R5) ; IS VOLUME VALID ALREADY SET BNE 1$ ; IF NE YES, SKIP MOUNTED TEST ; THE FOLLOWING IS LEFT AS COMMENTS FOR ; ARCHAEOLOGICAL PURPOSES. VER... HAS LONG ; SINCE SHUFFLED OFF ITS MORTAL COIL ; ; CMP $VERTK,R0 ; REQUESTING TASK THE VERIFICATION TASK ? ; BEQ 1$ ; IF EQ, YES - ALLOW VV TO BE RESET ; NOW WE VALIDATE THAT THE DEVICE IS NOT MOUNTED. ; RECENT CHANGE: ALLOW RESET OF VOLUME VALID TO ; A MOUNTED VOLUME WITH NO ACP. THIS ALLOWS FOR ; BRU TO WORK AFTER COMPENSATING FOR VMS NOT FIXING ; THE RX50 DOOR PROBLEM. BITB #US.MNT,U.STS(R5) ; IS THE DEVICE ALREADY MOUNTED? BNE 1$ ; IF NE NO, OK TST U.ACP(R5) ; IS IT MOUNTED WITH AN ACP (F11 OR FOR)? BNE 50$ ; IF NE YES, ERROR ; IF WE GET HERE, IT'S OK TO DO VOLUME VALID ; FUNCTIONS ON THIS VOLUME, FOR THIS TASK. GET ; THE SUBFUNCTION TYPE, AND DISPATCH ALL FUNCTIONS ; BUT SIZE. 1$: MOV I.PRM+2(R1),R0 ; GET PARAMETER SPECIFICATION BPL 2$ ; IF PL SET/CLEAR OR LOAD/UNLOAD ; IT'S VV$SIZ, SET UP THE QIO FOR THE DRIVER. MOV I.PRM+14(R1),I.PRM+16(R1) ; MOVE REGISTER BUFFER ADDRESS MOV I.PRM+12(R1),I.PRM+14(R1) ; TO PROPER PLACE FOR $CRPAS BR 15$ ; SHOW SUCCESS ; IT'S A SET OR CLEAR. BEGIN TO VALIDATE, ; SEPARATE VV$SET 2$: BIT #VV$SET,R0 ; SET VOLUME VALID? BNE 10$ ; IF NE YES ; IT WASN'T SET. IF IT WASN'T UNLOAD, IT'S AN ; INVALID SUBFUNCTION. BIT #^C,R0 ; BAD PARAMETERS? BNE 5$ ; IF NE YES ; IT WAS VV$UNL. UNSET VOLUME VALID FOR THE ; VOLUME AND COMPLETE SUCCESSFUL. BICB #US.VV,U.STS(R5); CLEAR VOLUME VALID BR 15$ ; RETURN SUCCESS ; I.PRM+2 WASN'T VV$SET, VV$UNL, OR VV$SIZ. ; RETURN IE.BAD 5$: MOV #IE.BAD&377,R0 ; ASSUME BAD PARAMETERS BR 40$ ; EXIT ; WE GET HERE FOR A CORRECTLY VALIDATED VV$SET. ; SET SOFTWARE VOLUME VALID, FALL THROUGH TO ; SUCCESS RETURN 10$: BISB #US.VV,U.STS(R5) ; SET VOLUME VALID ; SET UP FUNCTION CODE FOR SUCCESSFUL RETURN 15$: MOV #IS.SUC&377,R0 ; SHOW SUCCESSFUL FUNCTION ; SUCCESSFUL RETURN WITH C BIT CLEAR. 20$: CLC ; SHOW GOOD FUNCTION RETURN ; ; FUNCTION WAS A TRANSFER FUNCTION. TEST TO SEE ; IF VOLUME VALID IS SET FOR THE VOLUME. 30$: MOV #-1,R0 ;ASSUME GOOD TRANSFER FUNCTION BITB #US.VV,U.STS(R5);HAS VOLUME VALID BEEN SET? BNE 20$ ;IF NE YES, GO RETURN SUCCESS INDICATION ; TRANSFER FUNCTION WITH VOLUME VALID NOT ; SET. REJECT AS "DEVICE NOT READY". MOV #IE.DNR&377,R0 ;ELSE FORCE DRIVE NOT READY ; FAILURE RETURN. SET CARRY AND RETURN 40$: SEC ;SHOW FAILURE RETURN ; 50$: MOV #IE.PRI&377,R0 ;PRIVILEGE VIOLATION BR 40$ ; .END